desc:Bass Professor Mark II

/*****************************************************
Copyright (C) 2016 Stige T.
License: http://jsplugins.supermaailma.net/license.php
*****************************************************/

EffectName: Bass Professor II
VendorString: Stige T.
VendorVersion: 1000
UniqueId: 'BPR2'

slider1:0<-10,10,1>-Sub Bass
slider2:0<-10,10,1>-Lo Bass
slider3:0<-10,10,1>-Hi Bass
slider4:0<-10,10,1>-Fullness
slider5:0<-10,10,1>-Body
slider6:0<-10,10,1>-Presence
slider7:0<-10,10,1>-Treble

slider8:0<0,1,1{Off,On}>-Transients

slider10:0<0,10,0.1>-Process

slider12:0<0,10,0.1>-Dirt

slider14:30<20,100,10>-LF Cut

slider20:0<-20,20,1>-Output

slider21:0<-10,10,1>-Input Trim

filename:0,bassprofessormk2_gfx/bg.png
filename:1,bassprofessormk2_gfx/vsliderhandle.png

resource:0,1

@init

!"#define VAL(A) (A)" "//";

buildStr = "build 161007";

t001 = exp(-1/(srate*0.0001));
t005 = exp(-1/(srate*0.0005));
t01 = exp(-1/(srate*0.001));
t03 = exp(-1/(srate*0.003));
t05 = exp(-1/(srate*0.005));
t10 = exp(-1/(srate*0.01));
t20 = exp(-1/(srate*0.02));
t30 = exp(-1/(srate*0.03));
t50 = exp(-1/(srate*0.05));
t100 = exp(-1/(srate*0.1));
t200 = exp(-1/(srate*0.2));
t500 = exp(-1/(srate*0.5));
t1000 = exp(-1/(srate*1));
rmsw = 1-exp(-1/(3 / 1000 * srate));

function interpolate(A, B, X) (
  (A * (1 - X) + B * X);
);

function delay64spl(input) (
  this.x0 = input;
  this.x65=this.x64; this.x64=this.x63; this.x63=this.x62; this.x62=this.x61; this.x61=this.x60; this.x60=this.x59; this.x59=this.x58;
  this.x58=this.x57; this.x57=this.x56; this.x56=this.x55; this.x55=this.x54; this.x54=this.x53; this.x53=this.x52; this.x52=this.x51;
  this.x51=this.x50; this.x50=this.x49; this.x49=this.x48; this.x48=this.x47; this.x47=this.x46; this.x46=this.x45; this.x45=this.x44;  
  this.x44=this.x43; this.x43=this.x42; this.x42=this.x41; this.x41=this.x40; this.x40=this.x39; this.x39=this.x38; this.x38=this.x37;
  this.x37=this.x36; this.x36=this.x35; this.x35=this.x34; this.x34=this.x33; this.x33=this.x32; this.x32=this.x31; this.x31=this.x30;
  this.x30=this.x29; this.x29=this.x28; this.x28=this.x27; this.x27=this.x26; this.x26=this.x25; this.x25=this.x24; this.x24=this.x23;
  this.x23=this.x22; this.x22=this.x21; this.x21=this.x20; this.x20=this.x19; this.x19=this.x18; this.x18=this.x17; this.x17=this.x16;
  this.x16=this.x15; this.x15=this.x14; this.x14=this.x13; this.x13=this.x12; this.x12=this.x11; this.x11=this.x10; this.x10=this.x9;
  this.x9=this.x8; this.x8=this.x7; this.x7=this.x6; this.x6=this.x5; this.x5=this.x4; this.x4=this.x3; this.x3=this.x2; this.x2=this.x1; this.x1=this.x0;
  this.x65;
);

function megafilter(input)
instance(mX1,mX2,mY1,mY2,b0,b1,b2,a0,a1,a2,output)
(
  output = b0*input + b1*mX1 + b2*mX2 - a1*mY1 - a2*mY2;
  mX2 = mX1;
  mX1 = input;
  mY2 = mY1;
  mY1 = output;
);

function megafilter_init(freq,Q,gain,type)
instance(omega,tsin,tcos,alpha,b0,b1,b2,a0,a1,a2,A,beta)
(
  type = max(type,1);
  type = min(type,8);
  Q = max(Q,0.01);
  Q = min(Q,10);
  freq = max(freq,0.1);
  freq = min(freq,srate/2);

  A = pow(10.0,(gain/40.0));
  omega = 2*$pi*freq/srate;
  tsin = sin(omega);
  tcos = cos(omega);
  alpha = tsin/(2.0*Q);
  beta =sqrt(A)/Q;
  temp = freq+Q+gain+type;
  
  type == 1 ? (
  //low-shelf
  b0 = (A*((A+1.0)-(A-1.0)*tcos+beta*tsin));
  b1 = (2.0*A*((A-1.0)-(A+1.0)*tcos));
  b2 = (A*((A+1.0)-(A-1.0)*tcos-beta*tsin));
  a0 = ((A+1.0)+(A-1.0)*tcos+beta*tsin);
  a1 = (-2.0*((A-1.0)+(A+1.0)*tcos));
  a2 = ((A+1.0)+(A-1.0)*tcos-beta*tsin);
  );
  type == 2 ? (
  //hi-shelf
  b0 = (A*((A+1.0)+(A-1.0)*tcos+beta*tsin));
  b1 = (-2.0*A*((A-1.0)+(A+1.0)*tcos));
  b2 = (A*((A+1.0)+(A-1.0)*tcos-beta*tsin));
  a0 = ((A+1.0)-(A-1.0)*tcos+beta*tsin);
  a1 = (2.0*((A-1.0)-(A+1.0)*tcos));
  a2 = ((A+1.0)-(A-1.0)*tcos-beta*tsin);
  );
  type == 3 ? (
  //peak
  b0 = 1.0+alpha*A;
  b1 = -2.0*tcos;
  b2 = 1.0-alpha*A;
  a0 = 1.0+alpha/A;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha/A;
  );
  type == 4 ? (
  //low-pass
  b0 = (1-tcos)/2;
  b1 = 1-tcos;
  b2 = (1-tcos)/2;
  a0 = 1+alpha;
  a1 = -2*tcos;
  a2 = 1-alpha;
  );
  type == 5 ? (
  // hi-pass
  b0 = (1+tcos)/2;
  b1 = -(1+tcos);
  b2 = (1+tcos)/2;
  a0 = 1+alpha;
  a1 = -2*tcos;
  a2 = 1-alpha;
  );
  type == 6 ? (
  //band-pass
  b0 = alpha;
  b1 = 0.0;
  b2 = -alpha;
  a0 = 1.0+alpha;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha;
  );
  type == 7 ? (
  //notch
  b0 = 1.0;
  b1 = -2.0*tcos;
  b2 = 1.0;
  a0 = 1.0+alpha;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha;
  );
  type == 8 ? (
  //all-pass
  b0 = 1.0-alpha;
  b1 = -2.0*tcos;
  b2 = 1.0+alpha;
  a0 = 1.0+alpha;
  a1 = -2.0*tcos;
  a2 = 1.0-alpha;
  );

  b0 /= a0;
  b1 /= a0;
  b2 /= a0;
  a1 /= a0;
  a2 /= a0;
);

function HFLF_init(freq)
instance(n0,weight)
(
  n0 = 0;
  weight = 1-exp(-2*$pi*freq/srate);
);

function HFcut(input)
instance(out,n0,weight)
(  
  out = (n0+=((input-n0)*weight));
);

function LFcut(input)
instance(out,n0,weight)
(
  out = input - (n0+=((input-n0)*weight));
);

function follower(input,att,rel)
instance (env,tmp) (
  tmp = input;
  (tmp > env) ? (
      env = att * (env - tmp) + tmp;
  ) : (
      env = rel * (env - tmp) + tmp;
  );
);

function compressor_init(att,rel,dcomp,ucomp)
instance(attack,release,drive,boost)
(
  attack = exp(-1/(srate*att/1000));
  release = exp(-1/(srate*rel/1000));
  drive = dcomp;
  boost = ucomp;
);

function compressor(input)
instance(env,e1,e2,e3,attack,release,drive,boost)
(
  env = e1.follower(abs(input)*drive,attack,release);
  env = e2.follower(env,0,t20);
  env = e3.follower(env,0,t20);
  env = 1/(env+boost);
  input * env;
);

function masterCompressor(input)
instance(env,e1,e2,e3,attack,release,drive,boost,att)
(
  env = e1.follower(att.HFcut(abs(input))*drive,attack,release);
  env = e2.follower(env,0,t20);
  env = e3.follower(env,0,t20);
  env = 1/(env+boost);
  this.delay64spl(input) * env;
  //input * env;
);

function gate(input)
(
  this.splcount += 1;
  !(this.splcount % 10) ? (
    this.gate = this.e0.follower(min(abs(input),0.01)/0.01,0,t10);
    this.gate = this.e1.follower(this.gate,0,t03);
    this.splcount = 0;
  );
  input * this.gate;
);

function overdrive(input,gain)
instance(f1,f2,f3,f4,rms,s1,f5,gate)
(
  gain ? (
    input = f1.megafilter(input);
    input = f5.megafilter(input);
    
    !(this.splcount % 100) ? (
      rms = sqrt(s1 += rmsw * ( input^2 - s1 ));
      rms = 0.0001/(rms+0.0001) * 100; 
      rms = min(rms,(15 * dirt) + 5);
      this.splcount = 0;
    );
    this.splcount += 1;

    input = input * rms;
    input = atan(input*gain*800) * (0.03 + gain*0.01);
    input = f2.megafilter(input);
    input = f3.megafilter(input);
    input = f4.megafilter(input);
  );
);

function process_sliders() (

  f0.g =  10 ^ (slider1 * 2 / 20);
  f1.g =  10 ^ (slider2 * 2 / 20);
  f2.g =  10 ^ (slider3 * 2 / 20);
  f3.g =  10 ^ (slider4 * 2 / 20);
  f4.g =  10 ^ (slider5 * 2 / 20);
  f5.g =  10 ^ (slider6 * 2 / 20);
  f6.g =  10 ^ (slider7 * 2 / 20);
  
  out = 10 ^ (slider20 / 20);
  dcomp = interpolate(1,20,slider10/10);
  ucomp = interpolate(1,0.2,(slider10^0.5*3)/10);
  release = interpolate(10,120,slider10/10);
  attack = slider8;
  mcdrive = interpolate(1,1.68,slider10/10);
  lfcut = slider14;
  dirt = slider12/10;

  this.tmp.attrel != slider8+slider10+1000 ? (
    c0.compressor_init(interpolate(20,30,attack),release+30,dcomp,ucomp);
    c1.compressor_init(interpolate(20,30,attack),release+30,dcomp,ucomp);
    c2.compressor_init(interpolate(10,20,attack),release+30,dcomp,ucomp);
    c3.compressor_init(interpolate(5,10,attack),release+200,dcomp,(ucomp + 1) * 0.5);
    c4.compressor_init(interpolate(5,15,attack),release+20,dcomp,(ucomp + 1) * 0.5);
    c5.compressor_init(interpolate(0,5,attack),release+10,dcomp,ucomp);
    c6.compressor_init(interpolate(0,1,attack),release,dcomp * 2,ucomp);
    c7.att.HFLF_init(interpolate(1000,100,attack));
    c7.compressor_init(0,release,1,1);
    this.tmp.attrel = slider8+slider10+1000;
  );
  
  this.tmp.lfcut != lfcut ? (  
    f7.HFLF_init(lfcut);
    this.tmp.lfcut = lfcut;
  );
  
  this.tmp.s4 != slider4+1000 ? (  
    f8.megafilter_init(300,1,min(slider4,0),3);
    this.tmp.s4 == slider4+1000;
  );

  s22.checked && lastchecked != 1 ? (
    s23.checked = 0;
    slider21 = -6;
    lastchecked = 1;
  );
  s23.checked && lastchecked != 2 ? (
    s22.checked = 0;
    slider21 = 6;
    lastchecked = 2;
  );
  !s22.checked && !s23.checked ? (
    slider21 = 0;
    lastchecked = 0;
  );  
  
  itrim = 10 ^ (slider21 / 20);
  otrim = (1/(10 ^ (slider21 * 0.5 / 20))) *  1.41 * out;  

);
  
f0.megafilter_init(30,1,0,6);
f1.megafilter_init(80,2,0,6);
f2.megafilter_init(120,2,0,6);
f3.megafilter_init(300,1,0,6);
f4.megafilter_init(500,2,0,6);
f5.megafilter_init(1800,1,0,6);
f6.megafilter_init(4500,1,0,6);

od.f1.megafilter_init(2000,1,0,5);
od.f2.megafilter_init(1000,0.5,0,4);
od.f3.megafilter_init(1000,0.5,0,8);
od.f4.megafilter_init(600,0.9,0,5);
od.f5.megafilter_init(1200,2,-20,3);

mtr_x = 260;
mtr_y = 70;

pdc_delay = 64;
pdc_bot_ch = 0; pdc_top_ch = 2;

@slider

s1.value = slider1;
s2.value = slider2;
s3.value = slider3;
s4.value = slider4;
s5.value = slider5;
s6.value = slider6;
s7.value = slider7;
s10.value = slider10;
s12.value = slider12;
s14.value = slider14;
s20.value = slider20;

s8.checked = slider8;

s22.checked = slider21 == -6 ? 1;
s23.checked = slider21 == 6 ? 1;

process_sliders();

@block

norm = (rand(1) * 0.0000000001);

abs(in) > 0.001 ? (
  mtr0 = c0.env;
  mtr1 = c1.env;
  mtr2 = c2.env;
  mtr3 = c3.env;
  mtr4 = c4.env;
  mtr5 = c5.env;
  mtr6 = c6.env;
  mtr7 = c7.env;
) : (
  mtr0 = ((mtr0 * 100) + 1) * 0.0099;
  mtr1 = ((mtr1 * 100) + 1) * 0.0099;
  mtr2 = ((mtr2 * 100) + 1) * 0.0099;
  mtr3 = ((mtr3 * 100) + 1) * 0.0099;
  mtr4 = ((mtr4 * 100) + 1) * 0.0099;
  mtr5 = ((mtr5 * 100) + 1) * 0.0099;
  mtr6 = ((mtr6 * 100) + 1) * 0.0099;
  mtr7 = ((mtr7 * 100) + 1) * 0.0099;
);

@sample

in = (spl0 + norm) * itrim;

f3.g < 1 ? (
  in = f8.megafilter(in);
);


bp0 = f0.megafilter(in);
bp1 = f1.megafilter(in);
bp2 = f2.megafilter(in);
bp3 = f3.megafilter(in);
bp4 = f4.megafilter(in);
bp5 = f5.megafilter(in);
bp6 = f6.megafilter(in);

process = c0.compressor(bp0) * f0.g * 0.708 - (bp1 * 0.25);
process += c1.compressor(bp1) * f1.g;
process += c2.compressor(bp2) * f2.g;
process += c3.compressor(bp3) * f3.g;
process += c4.compressor(bp4) * f4.g * 1.19 - (bp3 * 0.25);
process += c5.compressor(bp5) * f5.g * 1.41  - (bp4 * 0.75);
process += c6.compressor(bp6) * f6.g * 1.68;

process = f7.LFcut(process);

dirt ? (
  process += od.overdrive(gt.gate(process),dirt);
);

process = c7.masterCompressor(process * mcdrive);

spl0 = spl1 = process * otrim;

@gfx 720 420

gfx_x = gfx_y = 0;
gfx_blit(0,1,0);

function draw_vslider(x,y,w,h,f,t,s,d,unit,title) (

  // Change detecion
  this.value.temp != this.value ? (
    _sliderDirty = 1;
    this.value.temp = this.value;
  );

  // Knob parameters
  this.knob.h = 22; // The actual handle height
  this.knob.hh = this.knob.h * 0.5;
  this.range = abs(f - t);

  // Mouse Logic
  mouse_x >= x && mouse_x <= x+w && mouse_y >= y && mouse_y <= y+h && !this.disabled ? (
    !mouse_cap ? this.hasEntered = 1;
    mouse_cap ? this.hasClicked = 1;
    this.hasEntered && this.hasClicked ? this.canChange = 1;
  ) : (
    this.hasEntered = this.hasClicked = 0;
  );
  !mouse_cap ? (this.canChange = 0; this.init_x = 0;);
  
  // Process
  this.canChange ? (
    mouse_cap & 8 ? (
      !this.init_y ? this.init_y = mouse_y;
      this.knob.input = (this.init_y - y - this.knob.h) + (((mouse_y/this.init_y) - 1) * 10 + this.knob.hh);
    ) : (
      this.knob.input = -(mouse_y - y - h + this.knob.hh);
      this.init_y = 0;
    );
    
    this.knob.input.normalized = (this.knob.input / (h-this.knob.hh+2));
    this.value.rect = this.range * this.knob.input.normalized;
    this.step = 1/s;
    this.value.rect = ceil(this.value.rect * this.step) / this.step;
    this.value = this.value.rect + f;
    
    mouse_cap & 4 ? this.value = d;
  );
  
  this.value = max(min(this.value,t),f);
  this.knob.pos = (this.range - this.value + f ) / (this.range) * (h-this.knob.h);
  
  // Knob  
  gfx_y = y+this.knob.pos-8; gfx_x = x;
  gfx_blit(1,1,0);
  
  // Title
  gfx_r = gfx_g = gfx_b = 0.7;
  this.str1 = title;
  gfx_measurestr(this.str1,this.str1.w,this.str1.h);
  gfx_y = y - this.str1.h - 5; gfx_x = x + (w * 0.5) - (this.str1.w * 0.5);
  gfx_drawstr(this.str1);  
  
  // Readout
  !this.hidereadout ? (
    gfx_r = gfx_g = gfx_b = 0.55;
    this.str2 = strcat(sprintf(#,"%.2f",this.value),unit);
    gfx_measurestr(this.str2,this.str2.w,this.str2.h);
    gfx_y = y + h + 5; gfx_x = x + (w * 0.5) - (this.str2.w * 0.5);
    gfx_drawstr(this.str2);
  );
  
  this.value;
);

function draw_chkbox(x,y,s,title)
(

  // Change detecion
  this.checked.temp != this.checked ? (
    _sliderDirty = 1;
    this.checked.temp = this.checked;
  );

  gfx_r = gfx_g = gfx_b = 0.7;
  gfx_measurestr(title,this.str.w,this.str.h);
  gfx_x = x - this.str.w - 5; gfx_y = y + (s * 0.5) - (this.str.h * 0.5);
  gfx_drawstr(title);

  // Mouse Logic
  mouse_x >= x && mouse_x <= x+s && mouse_y >= y && mouse_y <= y+s && !this.disabled ? (
    !mouse_cap ? this.hasEntered = 1;
    mouse_cap ? this.hasClicked = 1;
    this.hasEntered && this.hasClicked ? this.canChange = 1;
  ) : (
    this.hasEntered = this.hasClicked = this.canChange = 0;
  );
  !mouse_cap ? (this.canChange = 0;);

  this.canChange ? (
    this.checked = 1-this.checked;
    this.hasEntered = this.hasClicked = this.canChange = 0;
  );

  // Frame
  gfx_r = gfx_g = gfx_b = 0.35;
  gfx_rect(x,y,s,s);
  gfx_r = gfx_g = gfx_b = 0.07;
  gfx_rect(x+1,y+1,s-2,s-2);
  
  // Checked
  this.checked ? (
    gfx_r = 0.9; gfx_g = 0.9; gfx_b = 1;
    gfx_rect(x+2,y+2,s-4,s-4);
  );
    
  this.checked; 
);

function dynmeter(in1,x_pos,y_pos,showval)
instance(redux,col1,col2,in1_gfx,in2_gfx,in3_gfx)
(
  gfx_r = 0.25; gfx_g = 0.25; gfx_b = 0.25; gfx_a = 0;
  gfx_x = x_pos; gfx_y = y_pos;
  gfx_rectto(200+x_pos,10+y_pos);
  gfx_r = 0; gfx_g = 0; gfx_b = 0; gfx_a = 0;
  gfx_x = x_pos+1; gfx_y = y_pos+1;
  gfx_rectto(199+x_pos,9+y_pos);
  gfx_r = 0.8; gfx_g = 0.8; gfx_b = 0.8; gfx_a = 0;
  showval ? (
    gfx_x = 199+x_pos; gfx_y = 10+y_pos;gfx_lineto(199+x_pos,20+y_pos,0);gfx_drawnumber(20,0);
    gfx_x = 161+x_pos; gfx_y = 10+y_pos;gfx_lineto(161+x_pos,20+y_pos,0);gfx_drawnumber(12,0);
    gfx_x = 130+x_pos; gfx_y = 10+y_pos;gfx_lineto(130+x_pos,20+y_pos,0);gfx_drawnumber(6,0);
    gfx_x = 100+x_pos; gfx_y = 10+y_pos;gfx_lineto(100+x_pos,20+y_pos,0);gfx_drawnumber(0,0);
    gfx_x = 69+x_pos; gfx_y = 10+y_pos;gfx_lineto(69+x_pos,20+y_pos,0);gfx_drawnumber(-6,0);
    gfx_x = 38+x_pos; gfx_y = 10+y_pos;gfx_lineto(38+x_pos,20+y_pos,0);gfx_drawnumber(-12,0);
    gfx_x = 0+x_pos; gfx_y = 10+y_pos;gfx_lineto(0+x_pos,20+y_pos,0);gfx_drawnumber(-20,0);
  );
  
  gfx_x = 101+x_pos; gfx_y = y_pos+2;
  in1 = max(in1,0.1);
  in1 = min(in1,10);
  gfx_a = 1;
  col1 = in1 >= 1 ? min(in1/4,1) : min((1/in1)/4,1);
  col2 = 1-col1;
  gfx_r = col1; gfx_g = col2; gfx_b = 0;  gfx_a = 0.7;
  in1_gfx = ceil(100 - log(1/in1)*43.3);
  gfx_rectto( in1_gfx + x_pos, 8 + y_pos);
    
  gfx_r = 0.5; gfx_g = 0.5; gfx_b = 0.5; gfx_a = 1;
  gfx_x = 100+x_pos; gfx_y = y_pos;
  gfx_rectto(101+x_pos,10+y_pos);
);

gfx_setfont(1,"Calibri",14,'b');

slider10 = s10.draw_vslider(50,80,20,220,0,10,0.5,0,"","");
slider12 = s12.draw_vslider(100,80,20,220,0,10,0.25,0,"","");

sld_x = 170;

slider1 = s1.draw_vslider(sld_x,230,20,150,-10,10,0.5,0,"","");
slider2 = s2.draw_vslider(sld_x + 60,230,20,150,-10,10,0.5,0,"","");
slider3 = s3.draw_vslider(sld_x + 120,230,20,150,-10,10,0.5,0,"","");
slider4 = s4.draw_vslider(sld_x + 180,230,20,150,-10,10,0.5,0,"","");
slider5 = s5.draw_vslider(sld_x + 240,230,20,150,-10,10,0.5,0,"","");
slider6 = s6.draw_vslider(sld_x + 300,230,20,150,-10,10,0.5,0,"","");
slider7 = s7.draw_vslider(sld_x + 360,230,20,150,-10,10,0.5,0,"","");

slider8 = s8.draw_chkbox(110,390,12,"");

slider14 = s14.draw_vslider(600,80,20,220,20,100,10,30,"Hz","");
slider20 = s20.draw_vslider(650,80,20,220,-20,20,0.5,0,"dB","");

s22.draw_chkbox(110,340,12,"");
s23.draw_chkbox(110,360,12,"");

_sliderDirty ? (
  process_sliders();  
  _sliderDirty = 0;
);

m0.dynmeter(mtr0,mtr_x,mtr_y,0);
m1.dynmeter(mtr1,mtr_x,9 + mtr_y,0);
m2.dynmeter(mtr2,mtr_x,18 + mtr_y,0);
m3.dynmeter(mtr3,mtr_x,27 + mtr_y,0);
m4.dynmeter(mtr4,mtr_x,36 + mtr_y,0);
m5.dynmeter(mtr5,mtr_x,45 + mtr_y,0);
m6.dynmeter(mtr6,mtr_x,54 + mtr_y,0);
m7.dynmeter(mtr7,mtr_x,73 + mtr_y,1);

gfx_x = 650; gfx_y = 395;
gfx_a = 0.9;
gfx_setfont(1,"Arial",11);
gfx_drawstr(buildStr);
